﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
using System.Text;

namespace Equation.Enterprise.Framework.Domain.Data
{
    public interface IRepository
    {
        /// <summary>
        /// Persist all changes
        /// </summary>
        /// <returns>Number of entities affected</returns>
        int SaveChanges();

        /// <summary>
        /// State if specified entity has been changed or not
        /// </summary>
        /// <param name="entity">Entity to be checked</param>
        /// <returns>Changed or not</returns>
        bool IsModified(object entity);

        /// <summary>
        /// Get the IUnitOfWork
        /// </summary>
        IUnitOfWork UnitOfWork { get; }


        /// <summary>
        /// Get current DbContext
        /// </summary>
        DbContext DbContext { get; }
    }

    public interface IRepository<T> : IRepository
    {
        /// <summary>
        /// Add a new entity to repository
        /// This entity hasn't been persisted until you call SaveChanges()
        /// </summary>
        /// <param name="entity">Entity to be added</param>
        void Add(T entity);

        /// <summary>
        /// Update an existing entity
        /// This entity hasn't been persisted untill you call SaveChanges()
        /// </summary>
        /// <param name="entity">Entity to be updated</param>
        void Update(T entity);

        /// <summary>
        /// Delete an existing entity
        /// This entity hasn't been removed untill you call SaveChanges()
        /// </summary>
        /// <param name="entity">Entity to be deleted</param>
        void Delete(T entity);

        /// <summary>
        /// Delete existing entities with a lamdda condition
        /// This entity hasn't been removed untill you call SaveChanges()
        /// </summary>
        /// <param name="where">Lambda condition to delete</param>
        void Delete(Expression<Func<T, bool>> where);

        /// <summary>
        /// Get an existing entity with indentity type of int
        /// </summary>
        /// <param name="id">Identity of entity</param>
        /// <returns>Entity with specified identity</returns>
        T Get(int id);

        /// <summary>
        /// Get an existing entity with a lambda condition
        /// If there are more than one entites match specified condition, the first entity will be returned
        /// </summary>
        /// <param name="where">Lambda condition</param>
        /// <returns>First entity matchs specified condition</returns>
        T Get(Expression<Func<T, bool>> where);
        
        /// <summary>
        /// Get all entities in system
        /// </summary>
        /// <returns></returns>
        IEnumerable<T> List();

        /// <summary>
        /// Get all entities match specified condition
        /// </summary>
        /// <param name="where">Lambda condition</param>
        /// <returns></returns>
        IEnumerable<T> List(Expression<Func<T, bool>> where);

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        IQueryable<T> GetQueryable();
        
        /// <summary>
        /// Count all entities in system
        /// </summary>
        /// <returns>Count number</returns>
        long Count();

        /// <summary>
        /// Count entities match a specified condition
        /// </summary>
        /// <param name="where">Lambda condition</param>
        /// <returns>Count number</returns>
        long Count(Expression<Func<T, bool>> where);
    }
}
